package com.bc.mcode.config;

import com.bc.mcode.util.ReflectUtil;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;

import java.sql.Connection;
import java.util.Map;
import java.util.Properties;

@Intercepts({@Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {Connection.class, Integer.class}
)})
public class SqlInterceptor implements Interceptor {
    private String sqlType;

    public SqlInterceptor() {
    }

    public Object intercept(Invocation invocation) throws Throwable {
        RoutingStatementHandler statementHandler = (RoutingStatementHandler)invocation.getTarget();
        BaseStatementHandler delegate = (BaseStatementHandler) ReflectUtil.getFieldValue(statementHandler, "delegate");
        BoundSql boundSql = delegate.getBoundSql();
        Object param = boundSql.getParameterObject();
        if (param instanceof Map) {
            Map<?, ?> map = (Map)param;
            String sql = boundSql.getSql();
            StringBuffer nowSql = new StringBuffer();
            if (map.containsKey("offset") && map.containsKey("pageSize") && map.get("offset") != null && map.get("pageSize") != null) {
                Integer offset = (Integer)map.get("offset");
                Integer pageSize = (Integer)map.get("pageSize");
                if ("mysql".equals(this.sqlType)) {
                    nowSql.append(sql);
                    if (sql.indexOf("limit") < 0) {
                        nowSql.append(" limit " + offset + "," + pageSize);
                    }

                    ReflectUtil.setFieldValue(boundSql, "sql", nowSql.toString());
                } else if ("oracle".equals(this.sqlType)) {
                    if (sql.indexOf("limit") > 0) {
                        nowSql.append(sql.substring(0, sql.indexOf("limit") - 1));
                        boundSql.setAdditionalParameter("pageSize", offset);
                        boundSql.setAdditionalParameter("offset", offset + pageSize);
                        nowSql.insert(0, "select g_t.*,rownum as gnm from(");
                        nowSql.insert(0, "select g_tt.* from (");
                        nowSql.append(")g_t where rownum <= ?");
                        nowSql.append(")g_tt where gnm > ?");
                    } else {
                        nowSql.append(sql);
                        int count = offset + pageSize;
                        nowSql.insert(0, "select g_t.*,rownum from(");
                        nowSql.insert(0, "select g_tt.* from (");
                        nowSql.append(")g_t where rownum >=" + offset);
                        nowSql.append(")g_tt where rownum < " + count);
                    }

                    ReflectUtil.setFieldValue(boundSql, "sql", nowSql.toString());
                }
            }
        }

        return invocation.proceed();
    }

    public Object plugin(Object target) {
        return target instanceof StatementHandler ? Plugin.wrap(target, this) : target;
    }

    public void setProperties(Properties properties) {
    }

    public String getSqlType() {
        return this.sqlType;
    }

    public void setSqlType(String sqlType) {
        this.sqlType = sqlType;
    }
}
